#pragma once
#include <queue>
#include <unistd.h>
#include <pthread.h>
#include <iostream>
#include <ctime>
using namespace std;
//线程池：1.任务队列，锁，条件变量，线程数量，获取任务，放入任务

const int g_num = 5;
template <typename T>
class ThreadPool
{
private:
    // 1.任务队列
    queue<T> _taskQ;
    //锁
    pthread_mutex_t _mutex;
    //条件变量
    pthread_cond_t _cond;
    //线程的数量
    int _num;
    static ThreadPool<T> *_ins;

private:
    ThreadPool(int nums = g_num) : _num(nums)
    {
        pthread_mutex_init(&_mutex, NULL);
        pthread_cond_init(&_cond, NULL);
    }
    ThreadPool(const T &tp) = delete;
    ThreadPool &operator=(const T &tp) = delete;

public:
    static ThreadPool<T>* GetInstance()
    {
        static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
        if (_ins == nullptr)
        {
            pthread_mutex_lock(&lock);
            if (_ins == nullptr)
            {
                _ins = new ThreadPool<T>();
            }
            pthread_mutex_unlock(&lock);
        }

        return _ins;
    }

private:
    bool IsEmpty()
    {
        return _taskQ.empty();
    }
    void Wait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    void Lock()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnLock()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void PopTask(T *task)
    {
        *task = _taskQ.front();
        _taskQ.pop();
    }
    void WakeUP()
    {
        pthread_cond_signal(&_cond);
    }

public:
    void PushTask(const T &task)
    {
        Lock();
        _taskQ.push(task);
        UnLock();

        WakeUP();
    }

    static void *HandlerThreadPool(void *args)
    {
        pthread_detach(pthread_self());
        ThreadPool<T> *tp = (ThreadPool<T> *)args;

        while (true)
        {
            tp->Lock();
            while (tp->IsEmpty())
            {
                tp->Wait();
            }
            //获取任务处理
            T t;
            tp->PopTask(&t);
            tp->UnLock();

            t.run();
        }
    }

public:
    void InitThreadPool()
    {
        pthread_t tid;
        for (int i = 0; i < _num; i++)
        {
            pthread_create(&tid, nullptr, HandlerThreadPool, this);
        }
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
};
template <class T>
ThreadPool<T> *ThreadPool<T>::_ins = nullptr;